using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenComposite.Base;
using OpenComposite.EII.Repository;

namespace OpenComposite.EII.Designer.BRules
{
	public partial class FormIFEntry : Form
	{
		#region Initialization
		public FormIFEntry(IServiceProvider serviceProvider, int idDomain, int workflowId)
		{
			InitializeComponent();

			this.TopLevel = false;

			exp1.WorkflowID = workflowId;
			_serviceProvider = serviceProvider;
			_idDomain = idDomain;
			_idWorkflow = workflowId;

			init();
		}
		private void init()
		{
			exp1.ServiceProvider = _serviceProvider;
			exp2.ServiceProvider = _serviceProvider;
		}
		#endregion

		#region Public Members

		#region Properties
		public IFSymbol.Condition Condition
		{
			get { return _condition; }
			set
			{
				if ( _condition != value ) {
					_condition = value;
					doConditionChanged();
				}
			}
		}
		#endregion

		#endregion

		#region Protected Members
		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);
			using ( Pen pen = new Pen(Color.FromArgb(127, 157, 185)) )
				e.Graphics.DrawRectangle(pen, 0, 0, this.Width - 1, this.Height - 1);
		}
		#endregion

		#region Private Members

		#region Variables
		private bool _bIsInExpTypeChanged = false;
		private bool _bSuspendValueChangedEvent = false;

		private int _idDomain = -1;
		private int _idWorkflow = -1;
		private IServiceProvider _serviceProvider;

		private IFSymbol.Condition _condition = null;
		#endregion

		#region Methods
		private void doConditionChanged()
		{
			this.SuspendLayout();
			_bIsInExpTypeChanged = true;
			_bSuspendValueChangedEvent = true;
			try {
				if ( _condition.LeftValueString.Trim() != "" ) {
					if ( _condition.LeftPart == IFSymbol.ConditionPartType.Rule ) {
						exp1.SetValue(_condition.LeftPart, _condition.LeftRuleID);
						RepositoryBusinessRule rule = exp1.Value as RepositoryBusinessRule;
						if ( rule != null )
							exp2.SetResultStrings(rule.Results);
					} else if ( _condition.LeftPart == IFSymbol.ConditionPartType.Variable ) {
						exp1.SetValue(_condition.LeftPart, _condition.LeftNounID);
					} else if ( _condition.LeftPart == IFSymbol.ConditionPartType.ProcessVariable ) {
						exp1.SetValue(_condition.LeftPart, _condition.LeftProcessVariableID);
					} else if ( _condition.LeftPart == IFSymbol.ConditionPartType.RuleConstant ) {
						exp1.SetValue(_condition.LeftPart, _condition.LeftRuleConstID);
					} else {
						exp1.SetValue(_condition.LeftPart, _condition.LeftValueString);
					}
				} else {
					exp1.Type = IFSymbol.ConditionPartType.Variable;
				}
				if ( _condition.RightValueString.Trim() != "" ) {
					if ( _condition.RightPart == IFSymbol.ConditionPartType.Rule ) {
						exp2.SetValue(_condition.RightPart, _condition.RightRuleID);
						RepositoryBusinessRule rule = exp2.Value as RepositoryBusinessRule;
						if ( rule != null )
							exp1.SetResultStrings(rule.Results);
					} else if ( _condition.RightPart == IFSymbol.ConditionPartType.Variable ) {
						exp2.SetValue(_condition.RightPart, _condition.RightNounID);
					} else if ( _condition.RightPart == IFSymbol.ConditionPartType.ProcessVariable ) {
						exp2.SetValue(_condition.RightPart, _condition.RightProcessVariableID);
					} else if ( _condition.RightPart == IFSymbol.ConditionPartType.RuleConstant ) {
						exp2.SetValue(_condition.RightPart, _condition.RightRuleConstID);
					} else {
						exp2.SetValue(_condition.RightPart, _condition.RightValueString);
					}
				}
				setOperators();
				foreach ( OpItem op in cmbOp.Items ) {
					if ( op.Operator == _condition.Operator ) {
						cmbOp.SelectedItem = op;
						break;
					}
				}
			} finally {
				_bIsInExpTypeChanged = false;
				_bSuspendValueChangedEvent = false;
				this.ResumeLayout(true);
			}
		}
		private void getPart(UCIFExpression exp, out IFSymbol.ConditionPartType partType,
			out string value, out string datatype, out int ruleid, out int nounid, out int rconstid, out int processvarid)
		{
			//bool getDatatype = false;
			//double d;
			object obj = exp.Value;
			datatype = "";
			ruleid = 0;
			nounid = 0;
			rconstid = 0;
			processvarid = 0;
			value = "";

			if ( exp.Type == IFSymbol.ConditionPartType.Rule ) {
				// Rule
				partType = IFSymbol.ConditionPartType.Rule;
				RepositoryBusinessRule rule = obj as RepositoryBusinessRule;
				if ( rule != null ) {
					ruleid = rule.ID;
					value = rule.Name;
				}
				//
			} else if ( exp.Type == IFSymbol.ConditionPartType.Variable ) {
				// Variable
				partType = IFSymbol.ConditionPartType.Variable;
				Noun noun = obj as Noun;
				if ( noun != null ) {
					nounid = noun.ID;
					value = noun.Name;
					datatype = noun.DataType;
				}
				//
			} else if ( exp.Type == IFSymbol.ConditionPartType.RuleConstant ) {
				// RuleConstant
				partType = IFSymbol.ConditionPartType.RuleConstant;
				RuleConstant rconst = obj as RuleConstant;
				if ( rconst != null ) {
					rconstid = rconst.ID;
					value = rconst.Name;
					datatype = rconst.DataType;
				}
				//
			} else if ( exp.Type == IFSymbol.ConditionPartType.Number ) {
				// Number
				partType = IFSymbol.ConditionPartType.Number;
				value = ( obj != null ? obj.ToString() : "0" );
				//getDatatype = true;
				//
			} else if ( exp.Type == IFSymbol.ConditionPartType.Boolean ) {
				// Boolean
				partType = IFSymbol.ConditionPartType.Boolean;
				value = ( obj != null ? obj.ToString() : true.ToString() );
				//getDatatype = true;
				//
			} else if ( exp.Type == IFSymbol.ConditionPartType.DateTime ) {
				// DateTime
				partType = IFSymbol.ConditionPartType.DateTime;
				if ( obj is DateTime )
					value = ( (DateTime)obj ).ToString();
				//
			} else if ( exp.Type == IFSymbol.ConditionPartType.ResultString ) {
				// ResultString
				partType = IFSymbol.ConditionPartType.String;
				value = ( obj != null ? obj.ToString() : "" );
				//
			} else if ( exp.Type == IFSymbol.ConditionPartType.ProcessVariable ) {
				// Process Variable
				partType = IFSymbol.ConditionPartType.ProcessVariable;
				WorkflowField field = obj as WorkflowField;
				if ( field != null ) {
					processvarid = field.ID;
					value = field.Name;
					datatype = field.DataType;
				}
			} else {
				// String
				partType = IFSymbol.ConditionPartType.String;
				value = ( obj != null ? obj.ToString() : "" );
				//
			}
		}

		private void setOperators()
		{
			cmbOp.BeginUpdate();
			try {
				bool isNumber = false;
				int selected = cmbOp.SelectedIndex;
				Noun n1 = exp1.Value as Noun;
				Noun n2 = exp2.Value as Noun;
				RuleConstant rc1 = exp1.Value as RuleConstant;
				RuleConstant rc2 = exp2.Value as RuleConstant;
				WorkflowField f1 = exp1.Value as WorkflowField;
				WorkflowField f2 = exp2.Value as WorkflowField;
				if ( ( n1 != null && getPartTypeOfDataType(n1.DataType) == IFSymbol.ConditionPartType.Number ) ||
					 ( n2 != null && getPartTypeOfDataType(n2.DataType) == IFSymbol.ConditionPartType.Number ) ||
					 ( rc1 != null && getPartTypeOfDataType(rc1.DataType) == IFSymbol.ConditionPartType.Number ) ||
					 ( rc2 != null && getPartTypeOfDataType(rc2.DataType) == IFSymbol.ConditionPartType.Number ) ||
					 ( f1 != null && getPartTypeOfDataType(f1.DataType) == IFSymbol.ConditionPartType.Number ) ||
					 ( f2 != null && getPartTypeOfDataType(f2.DataType) == IFSymbol.ConditionPartType.Number ) ) {
					isNumber = true;
				}
				cmbOp.Items.Clear();
				cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.Equals));
				cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.NotEquals));
				if ( exp1.Type == IFSymbol.ConditionPartType.Number ||
					 exp2.Type == IFSymbol.ConditionPartType.Number ||
					 exp1.Type == IFSymbol.ConditionPartType.DateTime ||
					 exp2.Type == IFSymbol.ConditionPartType.DateTime ||
					 isNumber ) {
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.Greater));
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.GreaterEquals));
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.Less));
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.LessEquals));
				} else if ( exp1.Type == IFSymbol.ConditionPartType.String ||
							exp2.Type == IFSymbol.ConditionPartType.String ) {
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.Contains));
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.NotContains));
				}
				if ( exp1.Type == IFSymbol.ConditionPartType.Variable ) {
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.HasValue));
					cmbOp.Items.Add(new OpItem(IFSymbol.ConditionOperator.HasNoValue));
				}
				if ( selected >= cmbOp.Items.Count )
					cmbOp.SelectedIndex = 0;
				else
					cmbOp.SelectedIndex = selected;
			} finally {
				cmbOp.EndUpdate();
			}
		}
		private void setExpType(UCIFExpression expBase, UCIFExpression expChange)
		{
			if ( _bIsInExpTypeChanged || expBase.Type == expChange.Type )
				return;
			this.SuspendLayout();
			_bIsInExpTypeChanged = true;
			try {
				if ( expBase.Type == IFSymbol.ConditionPartType.Variable ) {
					Noun n = expBase.Value as Noun;
					if ( n != null ) {
						expChange.Type = getPartTypeOfDataType(n.DataType);
					} else {
						expChange.Type = IFSymbol.ConditionPartType.String;
					}
				} else if ( expBase.Type == IFSymbol.ConditionPartType.Rule ) {
					expChange.SetValue(IFSymbol.ConditionPartType.ResultString, "");
				} else if ( expBase.Type == IFSymbol.ConditionPartType.RuleConstant ) {
					// do nothing !?
				} else if ( expBase.Type == IFSymbol.ConditionPartType.ProcessVariable ) {
					WorkflowField f = expBase.Value as WorkflowField;
					if ( f != null ) {
						expChange.Type = getPartTypeOfDataType(f.DataType);
					} else {
						expChange.Type = IFSymbol.ConditionPartType.String;
					}
				} else {
					expChange.Type = expBase.Type;
				}
				setOperators();
			} finally {
				_bIsInExpTypeChanged = false;
				this.ResumeLayout(true);
			}
		}
		private IFSymbol.ConditionPartType getPartTypeOfDataType(string strDataType)
		{
			IFSymbol.ConditionPartType parttype;
			string datatype = "," + strDataType.ToLower() + ",";

			if ( ",int,integer,decimal,double,single,float,long,byte,".Contains(datatype) )
				parttype = IFSymbol.ConditionPartType.Number;
			else if ( ",datetime,time,date,".Contains(datatype) )
				parttype = IFSymbol.ConditionPartType.DateTime;
			else if ( ",bool,boolean,".Contains(datatype) )
				parttype = IFSymbol.ConditionPartType.Boolean;
			else
				parttype = IFSymbol.ConditionPartType.String;

			return parttype;
		}
		private void doValueChanged(UCIFExpression expBase, UCIFExpression expChange)
		{
			if ( _bSuspendValueChangedEvent )
				return;

			_bSuspendValueChangedEvent = true;
			_bIsInExpTypeChanged = true;
			if ( expBase.Type == IFSymbol.ConditionPartType.Rule ) {
				RepositoryBusinessRule rule = expBase.Value as RepositoryBusinessRule;
				if ( rule != null ) {
					expChange.Type = IFSymbol.ConditionPartType.ResultString;
					expChange.SetResultStrings(rule.Results);
				}
			} else if ( expBase.Type == IFSymbol.ConditionPartType.Variable ) {
				Noun noun = expBase.Value as Noun;
				Noun nounChange = expChange.Value as Noun;
				if ( noun != null ) {
					if ( nounChange != null ) {
						if ( noun.DataType != nounChange.DataType )
							MessageBox.Show("The datatypes of the nouns you want to compare are not the same.", "Business Rule", MessageBoxButtons.OK, MessageBoxIcon.Information);
					} else {
						string datatype = "," + noun.DataType.ToLower() + ",";
						if ( ",int,integer,decimal,double,single,float,long,byte,".Contains(datatype) )
							expChange.Type = IFSymbol.ConditionPartType.Number;
						else if ( ",datetime,time,date,".Contains(datatype) )
							expChange.Type = IFSymbol.ConditionPartType.DateTime;
						else if ( ",bool,boolean,".Contains(datatype) )
							expChange.Type = IFSymbol.ConditionPartType.Boolean;
						else
							expChange.Type = IFSymbol.ConditionPartType.String;
					}
				}
			} if ( expBase.Type == IFSymbol.ConditionPartType.ProcessVariable ) {
				WorkflowField field = expBase.Value as WorkflowField;
				WorkflowField fieldChange = expChange.Value as WorkflowField;
				if ( field != null ) {
					if ( fieldChange != null ) {
						if ( field.DataType != fieldChange.DataType )
							MessageBox.Show("The datatypes of the process variables you want to compare are not the same.", "Business Rule", MessageBoxButtons.OK, MessageBoxIcon.Information);
					} else {
						string datatype = "," + field.DataType.ToLower() + ",";
						if ( ",int,integer,decimal,double,single,float,long,byte,".Contains(datatype) )
							expChange.Type = IFSymbol.ConditionPartType.Number;
						else if ( ",datetime,time,date,".Contains(datatype) )
							expChange.Type = IFSymbol.ConditionPartType.DateTime;
						else if ( ",bool,boolean,".Contains(datatype) )
							expChange.Type = IFSymbol.ConditionPartType.Boolean;
						else
							expChange.Type = IFSymbol.ConditionPartType.String;
					}
				}
			}
			setOperators();
			_bSuspendValueChangedEvent = false;
			_bIsInExpTypeChanged = false;
		}

		#endregion

		#region Event Handler

		private void FormIFEntry_FormClosing(object sender, FormClosingEventArgs e)
		{
			IFSymbol.ConditionPartType partType;
			string value;
			string datatype;
			int ruleid;
			int nounid;
			int rconstid;
			int processvarid;

			_condition = new IFSymbol.Condition(_serviceProvider);

			getPart(exp1, out partType, out value, out datatype, out ruleid, out nounid, out rconstid, out processvarid);
			_condition.LeftPart = partType;
			_condition.LeftValueString = value;
			_condition.LeftDataTypeString = datatype;
			_condition.LeftRuleID = ruleid;
			_condition.LeftNounID = nounid;
			_condition.LeftRuleConstID = rconstid;
			_condition.LeftProcessVariableID = processvarid;

			if ( cmbOp.SelectedItem is OpItem )
				_condition.Operator = ( (OpItem)cmbOp.SelectedItem ).Operator;
			else
				_condition.Operator = IFSymbol.ConditionOperator.Equals;

			getPart(exp2, out partType, out value, out datatype, out ruleid, out nounid, out rconstid, out processvarid);
			_condition.RightPart = partType;
			_condition.RightValueString = value;
			_condition.RightDataTypeString = datatype;
			_condition.RightRuleID = ruleid;
			_condition.RightNounID = nounid;
			_condition.RightRuleConstID = rconstid;
			_condition.RightProcessVariableID = processvarid;
		}

		private void exp1_ConditionPartTypeChanged(object sender, EventArgs e)
		{
			setExpType(exp1, exp2);
		}
		private void exp2_ConditionPartTypeChanged(object sender, EventArgs e)
		{
			setExpType(exp2, exp1);
		}

		private void exp1_ValueChanged(object sender, EventArgs e)
		{
			doValueChanged(exp1, exp2);
		}
		private void exp2_ValueChanged(object sender, EventArgs e)
		{
			doValueChanged(exp2, exp1);
		}

		private void cmbOp_SelectedIndexChanged(object sender, EventArgs e)
		{
			if ( !( cmbOp.SelectedItem is OpItem ) ) return;
			OpItem selected = (OpItem)cmbOp.SelectedItem;
			if ( selected.Operator == IFSymbol.ConditionOperator.HasNoValue ||
				 selected.Operator == IFSymbol.ConditionOperator.HasValue ) {
				exp2.Enabled = false;
			} else {
				exp2.Enabled = true;
			}
		}

		private void btnOK_Click(object sender, EventArgs e)
		{
			this.DialogResult = DialogResult.OK;
			this.Close();
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			this.DialogResult = DialogResult.Cancel;
			this.Close();
		}

		#endregion

		#endregion

		#region Struct: VarItem
		internal struct VarItem
		{
			public VarItem(IFSymbol.ConditionPartType type, string value)
			{
				this.Type = type;
				this.Value = value;
				this.DataType = "";
				this.RuleId = -1;
			}
			public VarItem(IFSymbol.ConditionPartType type, string value, string datatype)
			{
				this.Type = type;
				this.Value = value;
				this.DataType = datatype;
				this.RuleId = -1;
			}
			public VarItem(IFSymbol.ConditionPartType type, string value, int ruleid)
			{
				this.Type = type;
				this.Value = value;
				this.DataType = "";
				this.RuleId = ruleid;
			}
			public IFSymbol.ConditionPartType Type;
			public string Value;
			public string DataType;
			public int RuleId;

			public override string ToString()
			{
				if ( this.Type == IFSymbol.ConditionPartType.Rule )
					return string.Format("{0}:{1}:{2}", this.Type.ToString(), this.Value, this.RuleId);
				else if ( string.IsNullOrEmpty(this.DataType) || this.Type != IFSymbol.ConditionPartType.Variable )
					return string.Format("{0}:{1}", this.Type.ToString(), this.Value);
				else
					return string.Format("{0}:{1}:{2}", this.Type.ToString(), this.Value, this.DataType);
			}
		}
		#endregion
		#region Struct: OpItem
		internal struct OpItem
		{
			public OpItem(IFSymbol.ConditionOperator op)
			{
				this.Operator = op;
			}
			public IFSymbol.ConditionOperator Operator;
			public override string ToString()
			{
				return IFSymbol.Condition.GetConditionOperatorString(this.Operator);
			}
		}
		#endregion

		private void FormIFEntry_Leave(object sender, EventArgs e)
		{

		}

		protected override void OnParentChanged(EventArgs e)
		{
			OpenComposite.Base.Designer.DesignerViewPanel panel = this.Parent as OpenComposite.Base.Designer.DesignerViewPanel;
			if ( panel != null ) {
				panel.MouseClick += new MouseEventHandler(panel_MouseClick);
			}
			base.OnParentChanged(e);
		}

		void panel_MouseClick(object sender, MouseEventArgs e)
		{
			if ( !this.Bounds.Contains(e.Location) ) {
				this.Close();
			}
		}

	}
}
